package com.coocaa.x.uipackage.widget;

import android.animation.ValueAnimator;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ImageView;

import com.coocaa.x.framework.utils.LogUtils;
import com.coocaa.x.uipackage.BaseView;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by lu on 15-3-10.
 */
public class SlideFocusView extends BaseView {
    public static interface ISlideFocusView {
        void initSlideFocusView(SlideFocusView parent);
    }

    public static class FocusView extends ImageView {
        private int posX, posY;
        private int stepX, stepY;
        private int destWidth, destHeight;
        private int stepWidth, stepHeight;
        private float stepCount = 2.2f;
        private boolean executeAnim = false;
        private Context context = null;

        public FocusView(Context context) {
            super(context);
            this.context = context;
            // TODO Auto-generated constructor stub
        }

        // 移动到指定位置
        public void changeFocusPos(int posX, int posY, int destWidth, int destHeight) {
            executeAnim = true;
            this.posX = posX;
            this.posY = posY;
            this.destWidth = destWidth;
            this.destHeight = destHeight;
            beginAnimation();
            //initStep();
            //invalidate();
        }

        private void beginAnimation() {
            if (getWidth() == 0 || getHeight() == 0) {
                setFocusPos(posX, posY, destWidth, destHeight);
            } else {
                ValueAnimator animator = ValueAnimator.ofFloat(0.0f, 1.0f);
                final LayoutParams frameParams = (LayoutParams) getLayoutParams();
                final int x = frameParams.leftMargin;
                final int y = frameParams.topMargin;
                final int w = frameParams.width;
                final int h = frameParams.height;
                final int tempX = posX - frameParams.leftMargin;
                final int tempY = posY - frameParams.topMargin;
                final int tempW = destWidth - frameParams.width;
                final int tempH = destHeight - frameParams.height;
                animator.setDuration(100);
                animator.setInterpolator(new AccelerateDecelerateInterpolator());
                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float value = (Float) animation.getAnimatedValue();
                        setFocusPos(x + (int) (tempX * value),
                                y + (int) (tempY * value),
                                w + (int) (tempW * value),
                                h + (int) (tempH * value));
                    }
                });
                animator.start();
            }

        }

        // 直接设置位置到指定位
        public void setFocusPos(int posX, int posY, int destWidth, int destHeight) {
            LayoutParams frameParams = (LayoutParams) getLayoutParams();
            frameParams.leftMargin = posX;
            frameParams.topMargin = posY;
            frameParams.width = destWidth;
            frameParams.height = destHeight;
            setLayoutParams(frameParams);
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            // TODO Auto-generated method stub
            initStep();
            super.onSizeChanged(w, h, oldw, oldh);
        }

        private void initStep() {

        }
    }

    public static class FocusViewRevision {
        public int left, top,right,bottom;

        public FocusViewRevision(int width, int height) {
            this.left = width / 2;
            this.top = height / 2;
            this.right = left;
            this.bottom = top;
        }

        public FocusViewRevision(int left,int top,int right,int bottom){
            this.left = left;
            this.top = top;
            this.right = right;
            this.bottom = bottom;
        }
    }

    private abstract class IEvent<V, T> {
        protected final Map<V, T> eventListenerMap = new HashMap<V, T>();

        public void registerViewWithoutEvent(View view, FocusViewRevision rev) {
            if (rev != null) {
                synchronized (revMap) {
                    revMap.put(view, rev);
                }
            }
        }

        public void registerView(V view) {
            registerView(view, null, null);
        }

        public void registerView(V view, FocusViewRevision rev) {
            registerView(view, rev, null);
        }

        public void registerView(V view, FocusViewRevision rev, T listener) {
            if (rev != null) {
                synchronized (revMap) {
                    revMap.put(view, rev);
                }
            }
            if (listener != null) {
                synchronized (eventListenerMap) {
                    eventListenerMap.put(view, listener);
                }
            }
        }

        public void clearViewEventListener(V view) {
            if (view != null) {
                synchronized (eventListenerMap) {
                    eventListenerMap.remove(view);
                }
            }
        }
    }

    public class FocusChangedEvent extends IEvent<View, OnFocusChangeListener> implements
            OnFocusChangeListener {
        @Override
        public void registerView(View view, FocusViewRevision rev, OnFocusChangeListener listener) {
            view.setOnFocusChangeListener(this);
            super.registerView(view, rev, listener);
        }

        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            // TODO Auto-generated method stub
            OnFocusChangeListener listener = null;
            synchronized (eventListenerMap) {
                listener = eventListenerMap.get(v);
            }
            if (listener != null)
                listener.onFocusChange(v, hasFocus);
            if (!hasFocus) {
                hideFocusView();
                return;
            }

            showFocusView();
            updateFocusView(v);
        }
    }

    public class ItemSelectedEvent extends IEvent<AdapterView<?>, OnItemSelectedListener> implements
            OnItemSelectedListener {
        @Override
        public void registerView(AdapterView<?> view, FocusViewRevision rev,
                                 OnItemSelectedListener listener) {
            view.setOnItemSelectedListener(this);
            super.registerView(view, rev, listener);
        }

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            OnItemSelectedListener listener = null;
            synchronized (eventListenerMap) {
                listener = eventListenerMap.get(parent);
            }
            if (listener != null)
                listener.onItemSelected(parent, view, position, id);
            if (view == null)
                return;
            updateFocusView(parent,view);
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            // TODO Auto-generated method stub
            OnItemSelectedListener listener = null;
            synchronized (eventListenerMap) {
                listener = eventListenerMap.get(parent);
            }
            if (listener != null)
                listener.onNothingSelected(parent);
        }
    }

    private final Map<Object, FocusViewRevision> revMap = new HashMap<Object, FocusViewRevision>();

    protected FocusView focusView = null;
    private View currentFocusedView = null;
    public final FocusChangedEvent focusChangedEvent = new FocusChangedEvent();
    public final ItemSelectedEvent itemSelectedEvent = new ItemSelectedEvent();

    public SlideFocusView(Context context, int focusDrawable) {
        super(context);
        setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        focusView = new FocusView(context);
        focusView.setBackgroundResource(focusDrawable);
        focusView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));
        focusView.setFocusable(false);
        focusView.setFocusableInTouchMode(false);
        addView(focusView);
    }

    public void hideFocusView() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                focusView.setVisibility(View.GONE);
            }
        });
    }

    public void showFocusView() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                focusView.setVisibility(View.VISIBLE);
            }
        });
    }

    public FocusView getFocusView() {
        return focusView;
    }

    public void initChildView(ISlideFocusView i) {
        i.initSlideFocusView(this);
    }

    @Override
    public void addView(View child) {
        // TODO Auto-generated method stub
        super.addView(child);
        focusView.bringToFront();
    }

    @Override
    public void addView(View child, int index) {
        // TODO Auto-generated method stub
        super.addView(child, index);
        focusView.bringToFront();
    }

    @Override
    public void addView(View child, int width, int height) {
        // TODO Auto-generated method stub
        super.addView(child, width, height);
        focusView.bringToFront();
    }

    @Override
    public void addView(View child, ViewGroup.LayoutParams params) {
        // TODO Auto-generated method stub
        super.addView(child, params);
        focusView.bringToFront();
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        // TODO Auto-generated method stub
        super.addView(child, index, params);
        focusView.bringToFront();
    }

    private void updateFocusView(View v) {
        FocusViewRevision rev = null;
        synchronized (revMap) {
            rev = revMap.get(v);
        }
        updateFocusView(v, rev);
    }

    private void updateFocusView(View parent,View v){
        FocusViewRevision rev = null;
        synchronized (revMap) {
            rev = revMap.get(parent);
        }
        updateFocusView(v,rev);
    }

    private void updateFocusView(View v, FocusViewRevision rev) {
        final int[] to = new int[2];
        v.getLocationInWindow(to);
        int _focusViewWidth = v.getWidth();
        int _focusViewHeight = v.getHeight();
        if (rev != null) {
            _focusViewWidth += rev.left + rev.right;
            _focusViewHeight += rev.top + rev.bottom;
            to[0] -= rev.left;
            to[1] -= rev.top;
        }
        LogUtils.i("OOO", "to:" + to[0] + "," + to[1]);
        if (currentFocusedView == null) {
            currentFocusedView = v;
            focusView.setFocusPos(to[0], to[1], _focusViewWidth, _focusViewHeight);
            return;
        }
        focusView.changeFocusPos(to[0], to[1], _focusViewWidth, _focusViewHeight);
    }

    public void directlySetFocus(View v, int posX, int posY) {
        FocusViewRevision rev = null;
        synchronized (revMap) {
            if (!revMap.containsKey(v) || focusView == null)
                return;
            rev = revMap.get(v);
        }
        final int[] to = new int[2];
        to[0] = posX;
        to[1] = posY;
        int _focusViewWidth = v.getWidth();
        int _focusViewHeight = v.getHeight();
        if (rev != null) {
            _focusViewWidth += rev.left + rev.right;
            _focusViewHeight += rev.top + rev.bottom;
            to[0] -= rev.left;
            to[1] -= rev.top;
        }
        LogUtils.i("OOO", "to:" + to[0] + "," + to[1]);
        if (currentFocusedView == null) {
            currentFocusedView = v;
        }

        focusView.executeAnim = true;
        focusView.posX = to[0];
        focusView.posY = to[1];
        focusView.destWidth = _focusViewWidth;
        focusView.destHeight = _focusViewHeight;
        focusView.setFocusPos(to[0], to[1], _focusViewWidth, _focusViewHeight);
    }
}
